import math


class MathUtils:
    """数学计算工具类"""

    @staticmethod
    def calculate_percentage(value, total):
        """计算百分比

        Args:
            value: 数值
            total: 总数

        Returns:
            float: 百分比值（0-100）
        """
        if total == 0:
            return 0.0

        return (value / total) * 100

    @staticmethod
    def round_to_decimal(value, decimals=2):
        """四舍五入到指定小数位数

        Args:
            value: 要四舍五入的数值
            decimals: 小数位数

        Returns:
            float: 四舍五入后的数值
        """
        return round(value, decimals)

    @staticmethod
    def calculate_percentage_difference(value1, value2):
        """计算两个数值的百分比差异

        Args:
            value1: 第一个数值
            value2: 第二个数值

        Returns:
            float: 百分比差异
        """
        if value2 == 0:
            return 0.0 if value1 == 0 else float("inf")

        return ((value1 - value2) / value2) * 100

    @staticmethod
    def calculate_average(values):
        """计算平均值

        Args:
            values: 数值列表

        Returns:
            float: 平均值
        """
        if not values or len(values) == 0:
            return 0.0

        return sum(values) / len(values)

    @staticmethod
    def calculate_median(values):
        """计算中位数

        Args:
            values: 数值列表

        Returns:
            float: 中位数
        """
        if not values or len(values) == 0:
            return 0.0

        # 排序
        sorted_values = sorted(values)
        n = len(sorted_values)

        # 如果长度是偶数，取中间两个数的平均值
        if n % 2 == 0:
            return (sorted_values[n // 2 - 1] + sorted_values[n // 2]) / 2
        else:
            # 如果长度是奇数，取中间的数
            return sorted_values[n // 2]

    @staticmethod
    def calculate_mode(values):
        """计算众数

        Args:
            values: 数值列表

        Returns:
            list: 众数列表（可能有多个）
        """
        if not values or len(values) == 0:
            return []

        # 计算每个值出现的频率
        frequency = {}
        for value in values:
            if value in frequency:
                frequency[value] += 1
            else:
                frequency[value] = 1

        # 找出最大频率
        max_frequency = max(frequency.values())

        # 找出所有众数
        mode_values = [
            value
            for value, count in frequency.items()
            if count == max_frequency
        ]

        return mode_values

    @staticmethod
    def calculate_variance(values):
        """计算方差

        Args:
            values: 数值列表

        Returns:
            float: 方差
        """
        if not values or len(values) == 0:
            return 0.0

        mean = MathUtils.calculate_average(values)
        variance = sum((x - mean) ** 2 for x in values) / len(values)

        return variance

    @staticmethod
    def calculate_standard_deviation(values):
        """计算标准差

        Args:
            values: 数值列表

        Returns:
            float: 标准差
        """
        variance = MathUtils.calculate_variance(values)
        return math.sqrt(variance)

    @staticmethod
    def calculate_covariance(values1, values2):
        """计算协方差

        Args:
            values1: 第一个数值列表
            values2: 第二个数值列表

        Returns:
            float: 协方差
        """
        if (
            not values1
            or not values2
            or len(values1) != len(values2)
            or len(values1) == 0
        ):
            return 0.0

        mean1 = MathUtils.calculate_average(values1)
        mean2 = MathUtils.calculate_average(values2)

        covariance = sum(
            (values1[i] - mean1) * (values2[i] - mean2)
            for i in range(len(values1))
        ) / len(values1)

        return covariance

    @staticmethod
    def calculate_correlation(values1, values2):
        """计算相关系数

        Args:
            values1: 第一个数值列表
            values2: 第二个数值列表

        Returns:
            float: 相关系数（-1到1之间）
        """
        if (
            not values1
            or not values2
            or len(values1) != len(values2)
            or len(values1) == 0
        ):
            return 0.0

        covariance = MathUtils.calculate_covariance(values1, values2)
        std_dev1 = MathUtils.calculate_standard_deviation(values1)
        std_dev2 = MathUtils.calculate_standard_deviation(values2)

        if std_dev1 == 0 or std_dev2 == 0:
            return 0.0

        return covariance / (std_dev1 * std_dev2)

        if std_dev1 == 0 or std_dev2 == 0:
            return 0.0

        covariance = MathUtils.calculate_covariance(values1, values2)
        correlation = covariance / (std_dev1 * std_dev2)

        return correlation

    @staticmethod
    def calculate_z_score(value, mean, std_dev):
        """计算Z-score

        Args:
            value: 数值
            mean: 平均值
            std_dev: 标准差

        Returns:
            float: Z-score
        """
        if std_dev == 0:
            return 0.0

        return (value - mean) / std_dev

    @staticmethod
    def calculate_interquartile_range(values):
        """计算四分位数间距

        Args:
            values: 数值列表

        Returns:
            float: 四分位数间距
        """
        if not values or len(values) == 0:
            return 0.0

        # 排序
        sorted_values = sorted(values)
        n = len(sorted_values)

        # 计算Q1和Q3
        q1_index = int(n * 0.25)
        q3_index = int(n * 0.75)

        q1 = sorted_values[q1_index]
        q3 = sorted_values[q3_index]

        # 计算四分位数间距
        iqr = q3 - q1

        return iqr

    @staticmethod
    def calculate_median_absolute_deviation(values):
        """计算中位数绝对偏差

        Args:
            values: 数值列表

        Returns:
            float: 中位数绝对偏差
        """
        if not values or len(values) == 0:
            return 0.0

        median = MathUtils.calculate_median(values)
        absolute_deviations = [abs(x - median) for x in values]
        mad = MathUtils.calculate_median(absolute_deviations)

        return mad

    @staticmethod
    def calculate_weighted_average(values, weights):
        """计算加权平均值

        Args:
            values: 数值列表
            weights: 权重列表

        Returns:
            float: 加权平均值
        """
        if (
            not values
            or not weights
            or len(values) != len(weights)
            or len(values) == 0
        ):
            return 0.0

        # 检查权重是否都为0
        total_weight = sum(weights)
        if total_weight == 0:
            return 0.0

        # 计算加权平均值
        weighted_sum = sum(values[i] * weights[i] for i in range(len(values)))
        weighted_average = weighted_sum / total_weight

        return weighted_average

    @staticmethod
    def calculate_weighted_variance(values, weights):
        """计算加权方差

        Args:
            values: 数值列表
            weights: 权重列表

        Returns:
            float: 加权方差
        """
        if (
            not values
            or not weights
            or len(values) != len(weights)
            or len(values) == 0
        ):
            return 0.0

        # 检查权重是否都为0
        total_weight = sum(weights)
        if total_weight == 0:
            return 0.0

        # 计算加权平均值
        weighted_average = MathUtils.calculate_weighted_average(
            values, weights
        )

        # 计算加权方差
        weighted_variance = (
            sum(
                weights[i] * (values[i] - weighted_average) ** 2
                for i in range(len(values))
            )
            / total_weight
        )

        return weighted_variance

    @staticmethod
    def normalize(values):
        """归一化数值列表（0-1范围）

        Args:
            values: 数值列表

        Returns:
            list: 归一化后的数值列表
        """
        if not values or len(values) == 0:
            return []

        min_value = min(values)
        max_value = max(values)

        # 避免除以0
        if max_value - min_value == 0:
            return [0.0] * len(values)

        # 归一化
        normalized_values = [
            (value - min_value) / (max_value - min_value) for value in values
        ]

        return normalized_values

    @staticmethod
    def calculate_matching_score(value1, value2, threshold=0.8):
        """计算匹配得分

        Args:
            value1: 第一个值
            value2: 第二个值
            threshold: 匹配阈值

        Returns:
            float: 匹配得分
        """
        # 对于数值型数据，使用绝对差异或相对差异计算匹配得分
        if isinstance(value1, (int, float)) and isinstance(
            value2, (int, float)
        ):
            # 计算绝对差异
            absolute_diff = abs(value1 - value2)

            # 计算相对差异（避免除以0）
            if max(abs(value1), abs(value2)) == 0:
                relative_diff = 0
            else:
                relative_diff = absolute_diff / max(abs(value1), abs(value2))

            # 计算匹配得分（1 - 相对差异）
            score = 1 - relative_diff

            # 确保得分在0-1之间
            score = max(0, min(1, score))

            return score

        # 对于字符串型数据，这里简化实现，实际应用中可能需要更复杂的算法
        elif isinstance(value1, str) and isinstance(value2, str):
            # 获取最大长度
            max_len = max(len(value1), len(value2))

            # 计算相同字符的数量（简单实现）
            same_chars = 0
            for c1, c2 in zip(value1, value2):
                if c1 == c2:
                    same_chars += 1

            # 计算匹配得分
            score = same_chars / max_len if max_len > 0 else 1

            return score

        # 对于其他类型的数据，简单比较是否相等
        else:
            return 1.0 if value1 == value2 else 0.0

    @staticmethod
    def perform_statistical_analysis(data, columns=None):
        """执行统计分析

        Args:
            data: 数据，可以是pandas DataFrame或列表的列表
            columns: 列名列表

        Returns:
            dict: 统计分析结果
        """
        import pandas as pd

        # 确保数据是DataFrame格式
        if isinstance(data, pd.DataFrame):
            df = data
        else:
            if columns is None:
                columns = [f"Column {i + 1}" for i in range(len(data[0]))]
            df = pd.DataFrame(data, columns=columns)

        # 初始化结果字典
        analysis_results = {}

        # 对每一列进行统计分析
        for column in df.columns:
            # 跳过非数值型列
            if not pd.api.types.is_numeric_dtype(df[column]):
                continue

            column_data = df[column].dropna().tolist()

            # 计算统计指标
            stats = {
                "count": len(column_data),
                "mean": MathUtils.calculate_average(column_data),
                "median": MathUtils.calculate_median(column_data),
                "mode": MathUtils.calculate_mode(column_data),
                "min": min(column_data) if column_data else None,
                "max": max(column_data) if column_data else None,
                "range": (
                    max(column_data) - min(column_data)
                    if column_data
                    else None
                ),
                "variance": MathUtils.calculate_variance(column_data),
                "std_dev": MathUtils.calculate_standard_deviation(column_data),
                "q1": (
                    (
                        sorted(column_data)[int(len(column_data) * 0.25)]
                        if column_data
                        else None
                    )
                ),
                "q3": (
                    (
                        sorted(column_data)[int(len(column_data) * 0.75)]
                        if column_data
                        else None
                    )
                ),
                "iqr": MathUtils.calculate_interquartile_range(column_data),
                "mad": (
                    MathUtils.calculate_median_absolute_deviation(column_data)
                ),
            }

            analysis_results[column] = stats

        return analysis_results

    @staticmethod
    def calculate_confidence_interval(data, confidence_level=0.95):
        """计算置信区间

        Args:
            data: 数值列表
            confidence_level: 置信水平

        Returns:
            tuple: (下限, 上限)
        """
        if not data or len(data) <= 1:
            return (None, None)

        # 计算样本均值和样本标准差
        n = len(data)
        mean = MathUtils.calculate_average(data)
        std_dev = MathUtils.calculate_standard_deviation(data)

        # 计算标准误差
        standard_error = std_dev / math.sqrt(n)

        # 根据置信水平计算Z分数
        z_scores = {0.90: 1.645, 0.95: 1.96, 0.99: 2.576}
        z_score = z_scores.get(confidence_level, 1.96)  # 默认95%置信水平

        # 计算置信区间
        margin_of_error = z_score * standard_error
        lower_bound = mean - margin_of_error
        upper_bound = mean + margin_of_error

        return (lower_bound, upper_bound)
